/**
 * 判断一个 9x9 的数独是否有效。只需要验证已填入的数字是否有效，不验证数独是否可解。
 * @param {character[][]} board - 9x9 的数独棋盘，未填充的单元格用 '.' 表示
 * @return {boolean} - 如果数独有效返回 true，否则返回 false
 */
var isValidSudoku = function (board) {
  // 1. 检查每一行是否有效
  // 遍历每一行
  for (let i = 0; i < 9; i++) {
    // 使用 Set 存储当前行中出现的数字，Set 可以自动去重
    const row = new Set();
    // 遍历当前行的每个单元格
    for (let j = 0; j < 9; j++) {
      // 如果单元格为空（'.'），跳过不处理
      if (board[i][j] === '.') continue;
      // 如果当前数字已经在 Set 中，说明该行有重复，数独无效
      if (row.has(board[i][j])) return false;
      // 将当前数字添加到 Set 中
      row.add(board[i][j]);
    }
  }

  // 2. 检查每一列是否有效
  // 遍历每一列
  for (let j = 0; j < 9; j++) {
    // 使用 Set 存储当前列中出现的数字
    const col = new Set();
    // 遍历当前列的每个单元格
    for (let i = 0; i < 9; i++) {
      // 跳过空单元格
      if (board[i][j] === '.') continue;
      // 检查重复
      if (col.has(board[i][j])) return false;
      // 添加数字到 Set
      col.add(board[i][j]);
    }
  }

  // 3. 检查每个 3x3 子网格是否有效
  // 遍历每个 3x3 子网格（共 9 个）
  for (let blockRow = 0; blockRow < 3; blockRow++) {
    for (let blockCol = 0; blockCol < 3; blockCol++) {
      // 使用 Set 存储当前子网格中出现的数字
      const subgrid = new Set();
      // 遍历当前子网格的每个单元格
      for (let i = blockRow * 3; i < blockRow * 3 + 3; i++) {
        for (let j = blockCol * 3; j < blockCol * 3 + 3; j++) {
          // 跳过空单元格
          if (board[i][j] === '.') continue;
          // 检查重复
          if (subgrid.has(board[i][j])) return false;
          // 添加数字到 Set
          subgrid.add(board[i][j]);
        }
      }
    }
  }

  // 如果所有检查都通过，数独有效
  return true;
};